
class Random {
    static range(min, max) {
        return Math.floor(Math.random() * (max - min) + min);
    }
    static rangeRound(min, max) {
        return Math.round(Math.random() * (max - min) + min);
    }
    static rangeCeil(min, max) {
        return Math.ceil(Math.random() * (max - min) + min);
    }
    static bool(percent) {
        return (Math.random() < percent);
    }
    static selecter() {
        return arguments[Random.range(0, arguments.length)];
    }
};

//抽签
class RandomDraw {
    constructor(arr) {
        this.arr = [];
        this.reset(arr);
    }
    reset() {
        this.arr = arr.slice();
    }
    empty() {
        return this.arr.length == 0;
    }
    pick() {
        if (this.arr.length > 0) {
            return this.arr.splice(Random.range(0, this.arr.length), 1)[0];
        }
        else {
            return null;
        }
    }
};

//顺序抽取
class OrderDraw {
    constructor(arr, isLoop, isReverse) {
        this.arr = [];
        this.isLoop = isLoop;
        this.isReverse = isReverse;
        this.index = 0;
        this.reset(arr);
    }
    reset(arr) {
        this.index = 0;
        this.arr = arr.slice();
    }
    end() {
        if (this.isLoop) {
            return false;
        }

        if (this.isReverse) {
            this.index < 0;
        }
        else {
            this.index > this.arr.length - 1;
        }
    }
    pick() {
        if (this.end()) {
            return null;
        }
        let out = null;
        if (this.isReverse) {
            this.index--;
            if (this.index < 0) {
                this.index = this.arr.length - 1;
            }
            out = this.arr[this.index];
        }
        else {
            this.index++;
            if (this.index > this.arr.length - 1) {
                this.index = 0;
            }
            out = this.arr[this.index];
        }
        return out;
    }
};



class Drawer {
    //圆形算法。
    // 半径，圆心
    static circle(xc, yc, r) {
        var pointArr = [];
        var x = 0, y = r, yi, d;
        d = 3 - 2 * r;
        while (x <= y) {
            for (yi = x; yi <= y; yi++)
                Drawer._draw_circle_8(pointArr, xc, yc, x, yi);

            if (d < 0) {
                d = d + 4 * x + 6;
            } else {
                d = d + 4 * (x - y) + 10;
                y--;
            }
            x++;
        }

        //debug剔除重复点
        // for (let i = 0; i < pointArr.length;i++) {
        //     if (pointArr[i].x < 0 || pointArr[i].y < 0) {
        //     }
        //     else {
        //         for (let c = i + 1; c < pointArr.length;) {
        //             if (Contain.pp(pointArr[i], pointArr[c])) {
        //                 pointArr.splice(c, 1);
        //             }
        //             else {
        //                 c++;
        //             }
        //         }
        //     }
        // }

        //剔除重复点
        var tps = [];
        for (let i = 0; i < pointArr.length; i++) {
            var p = pointArr[i];
            var has = false;
            for (let c = 0; c < tps.length; c++) {
                if (tps[c].equals(p)) {
                    has = true;
                    break;
                }
            }
            if (!has) {
                tps.push(p);
            }
        }
        pointArr = tps;

        return pointArr;
    }
    static _draw_circle_8(arr, xc, yc, x, y) {
        arr.push(new Point(xc + x, yc + y));
        arr.push(new Point(xc + x, yc + y));
        arr.push(new Point(xc - x, yc + y));
        arr.push(new Point(xc + x, yc - y));
        arr.push(new Point(xc - x, yc - y));
        arr.push(new Point(xc + y, yc + x));
        arr.push(new Point(xc - y, yc + x));
        arr.push(new Point(xc + y, yc - x));
        arr.push(new Point(xc - y, yc - x));
    };
};


class UidCalculator {
    // static getRandomChar(){

    // }
    // static get09(){
    //     return Math.floor( Math.random()*10 );
    // }
    static get0x(x) {
        return Math.floor(Math.random() * x + 1);
    }
    static getUid() {
        return ("" + (new Date().getTime()) + UidCalculator.get0x(9999));
    }
};


/**
 * 带修饰的数值
 * 
 * NULL: 0,  //无，修饰无
 * 
 * NUMBER: 1, //数字，修饰无
 * 
 * STRING: 2, //文本，修饰无
 * 
 * PERCENT: 3, //百分比，修饰 [min,max]
 * 
 * LEVEL: 4, //层，修饰 [min,max,TAG1,min,max,TAG2]
 * 
 * POINTER: 5, //指针，指向某个对象
 * 
 * @param {Attribute.TYPE|JSON} data 类型或JSON
 * @param {null|Number|String} value 值
 * @param {null|Array} decorate 修饰
 */
class Attribute {
    constructor(data, value, decorate) {
        /**
         * 数值类型
         * @type {Attribute.TYPE}
         */
        this.type = Attribute.TYPE.NULL;
        /**
         * 值
         * @type {any}
         */
        this._value = null;
        /**
         * 修饰，规则语法参考类简介
         * @type {null|Array}
         */
        this.decorate = null;
        if (data) {
            if (typeof data == "number") {
                this.type = data;
                this._value = value;
                this.decorate = decorate || null;
            }
            else {
                this.type = data[0];
                this._value = data[1];
                this.decorate = data[2] || null;
            }
        }
    }
    /**
     * 只读，获取修饰后的数据
     * @returns {any}  
     */
    get valueDecorate() {
        switch (this.type) {
            case Attribute.TYPE.INTEGER:
                return Math.floor(this._value);
                break;
            case Attribute.TYPE.NUMBER:
                return utils.decimal(this._value, this.decorate[0]);
                break;
            case Attribute.TYPE.STRING:
                return this._value;
                break;
            case Attribute.TYPE.BOOLEAN:
                return !!this._value;
                break;
            case Attribute.TYPE.PERCENT:
                return (this._value + this.decorate[0]) / this.decorate[1];
                break;
            case Attribute.TYPE.LEVEL:
                // LEVEL: 4, //层，修饰 [0,2,TAG1,3,4,TAG2]
                for (let i = 0; i < this.decorate.length; i += 3) {
                    var min = this.decorate[i];
                    var max = this.decorate[i + 1];
                    var tag = this.decorate[i + 2];
                    if (this._value >= min && this._value < max) {
                        return tag;
                        break;
                    }
                }
                return "";
                break;
            case Attribute.TYPE.POINTER:
                return this._value;
                break;
            case Attribute.TYPE.RANDOM:
                this._value = Math.random() * (this.decorate[1] - this.decorate[0]) + this.decorate[0];
                return this._value;
            case Attribute.TYPE.FUNCTION:
                return this._value(...this.decorate);
            default:
                return null;
        }
    }
    /**
     * 原始数据
     * @param {any} val
     * @returns {any}  
     */
    get value() {
        return this._value;
    }
    set value(val) {
        this._value = val;
    }

    /**
     * 值真实类型是否数字
     * @returns {Boolean}
     */
    isNumber() {
        return this.type == Attribute.TYPE.INTEGER || this.type == Attribute.TYPE.NUMBER || this.type == Attribute.TYPE.PERCENT || this.type == Attribute.TYPE.LEVEL || this.type == Attribute.TYPE.RANDOM;
    }
    /**
     * 值真实类型是否文本
     * @returns {Boolean}
     */
    isString() {
        return this.type == Attribute.TYPE.LEVEL || this.type == Attribute.TYPE.STRING;
    }

    /**
     * 是function
     * 
     */
    isFunction() {
        return this.type == Attribute.TYPE.FUNCTION;
    }
    /**
     * @returns {Boolean}
     */
    isNull() {
        return this.type == Attribute.TYPE.NULL;
    }
    isBoolean() {
        return this.type == Attribute.TYPE.BOOLEAN;
    }
    /**
     * 克隆
     * @returns {Attribute}
     */
    clone() {
        return new Attribute(this.toJSON());
    }
    /**
     * 计算，类型有t=,=,+,-,*,/,%,<{表达式}>
     * @param {String} type
     * @param {Attribute} other
     */
    calculation(type, other) {
        if (!type.match(/(?:\<\{)[^\}\>]+(?:\}\>)/g)) {
            switch (type) {
                case "d=": //修改修饰
                    this.decorate = other.decorate;
                    break;
                case "t="://修改类型，修饰
                    this.decorate = other.decorate;
                    this.type = other.type;
                    break;
                case "v=": //仅修改值
                    this.value = other.value;
                    break;
                case "=": //修改全部
                    this.decorate = other.decorate;
                    this.type = other.type;
                    this.value = other.value;
                    break;
                default:
                    if (!this.isNumber() || !other.isNumber()) {
                        return;
                    }
                    switch (type) {
                        case "+":
                            this.value += other.value;
                            break;
                        case "-":
                            this.value -= other.value;
                            break;
                        case "*":
                            this.value *= other.value;
                            break;
                        case "/":
                            this.value /= other.value;
                            break;
                        case "%":
                            this.value %= other.value;
                            break;
                    }
                    break;
            }

        }
        else {//type是表达式
            var rightStr = type;
            rightStr = rightStr.replace(/\s+/g, "").substring(2, r1.length - 2);
            rightStr = rightStr.replace(/sv/g, this.value).replace(/ov/g, other.value);
            var left = algebra.parse("x");
            var right = algebra.parse(rightStr);
            var eq = new algebra.Equation(left, right);
            var answer = eq.solveFor("x");
            this.value = answer.numer / answer.denom;

        }
    }

    /**
     * 比较，类型有 t==, ==, !=, >=, <=,>,<
     * @param {String} type 比较类型
     * @param {Attribute} other 比较参数
     * @returns {Boolean}
     */
    compare(type, other) {
        var isTypeSame = this.type == other.type;
        if (type == "t==") {
            return isTypeSame;
        }
        else if (!isTypeSame) {
            return false;
        }

        switch (type) {
            case "==":
                return this.valueDecorate == other.valueDecorate;
                break;
            case "!=":
                return this.valueDecorate != other.valueDecorate;
                break;
            default:
                if (!this.isNumber() || !other.isNumber()) {
                    return false;
                }
                switch (type) {
                    case ">":
                        return this.valueDecorate > other.valueDecorate;
                        break;
                    case "<":
                        return this.valueDecorate < other.valueDecorate;
                        break;
                    case "<=":
                    case "=<":
                        return this.valueDecorate <= other.valueDecorate;
                        break;
                    case ">=":
                    case "=>":
                        return this.valueDecorate >= other.valueDecorate;
                        break;
                }
        }
    }

    /**
     * 序列化，输出数组。
     * @returns {Array}
     */
    toJSON() {
        switch (this.type) {
            case Attribute.TYPE.INTEGER:
            case Attribute.TYPE.STRING:
                return [this.type, this.value];
                break;
            case Attribute.TYPE.NUMBER:
            case Attribute.TYPE.PERCENT:
            case Attribute.TYPE.LEVEL:
            case Attribute.TYPE.RANDOM:
                return [this.type, this.value, this.decorate];
                break;
            case Attribute.TYPE.POINTER:
            case Attribute.TYPE.NULL:
            default:
                return null;
                break;
        }
    }
};

Attribute.TYPE = {
    NULL: 0,  //无，修饰无
    INTEGER: 1, //整数，修饰，无
    NUMBER: 2, //数字，修饰[保留位数]
    STRING: 3, //文本，修饰无
    BOOLEAN: 4, //布尔，修饰无
    PERCENT: 5, //百分比，修饰 [min,max]
    LEVEL: 6, //层，修饰 [min,max,TAG1,min,max,TAG2]
    RANDOM: 7, //随机数，修饰[min,max]
    POINTER: 8, //指针，指向某个对象
    FUNCTION: 9,//函数，访问时会直接执行，修饰是参数
};

//弃用
Attribute.COMPARE_TYPE = {
    // "exist": 0,
    "==": 1,
    "t==": 2, //类型比较
    "!=": 3,
    ">=": 4,
    "<=": 5,
    ">": 6,
    "<": 7,
}



class ArrayUtils {
    //在數組中尋找元素
    static find(arr, obj, customCallback) {
        let cb = customCallback || function (a, b) {
            return a == b;
        }
        for (let i = 0; i < arr.length; i++) {
            if (cb(arr[i], obj, i)) {
                return i;
            }
        }
        return -1;
    }
    static findAll(arr, obj, customCallback) {
        let outs = [];
        let cb = customCallback || function (a, b) {
            return a == b;
        }
        for (let i = 0; i < arr.length; i++) {
            if (cb(arr[i], obj, i)) {
                outs.push(i);
            }
        }
        return outs;
    }
    //在數組中刪除元素
    static remove(arr, obj, customCallback) {
        var index = ArrayUtils.find(arr, obj, customCallback);
        if (index !== -1) {
            return arr.splice(index, 1)[0];
        }

        return null;
    }

    //在數組中添加元素
    static push(arr, obj) {
        arr.push(obj);
    }

};


class CollectionUtils {
    static has(col, key) {
        return col[key] !== undefined
    }

    static valid(col, key) {
        return col[key] !== undefined && col[key] !== null;
    }
};
class FakeRandom {
    constructor(minStep, maxStep, resetOnTrue, loop) {
        this._step = 0;
        this.maxStep = maxStep;
        this.minStep = minStep;
        this.loop = loop;
        this.resetOnTrue = resetOnTrue;
    }
    get step() {
        this._step++;
        if (this._step > this.maxStep) {
            if (this.loop) {
                this._step = 0;
            }
            else {
                this._step = this.maxStep;
            }
        }

        let b = this.rand();
        if (b && this.resetOnTrue) {
            this._step = 0;
        }

        return b;
    }
    rand() {
        if (this._step < this.minStep) {
            return false;
        }
        else {
            return Math.floor(Math.random() * this.maxStep) < this._step;
        }
    }
};



/**
 * @description
 * @author : wildptr
 * @qq : 309563528
 * @date : 2021-05-16
 * 
 * 同步状态机
 */
class SyncState {

    constructor() {
        this.states = {};
    }
    /**
     * 
     * @param key
     * @param src 原值
     * @param dst 目标值
     */
    statement(key, src, dst) {
        if( src === undefined ) {
            src = false;
        }
        if( dst === undefined ) {
            dst = true;
        }
        this.states[key] = [
            src,
            dst
        ];
    }

    assign(key, val) {
        this.states[key][0] = val;
    }

    inc(key, val) {
        if( val === undefined ) {
            val = 1;
        }
        this.states[key][0] += val;
    }

    /**
     * 删除状态
     * @param key 
     */
    del(key) {
        if (this.states[key]) {
            delete this.states[key];
        }
    }

    /**
     * 检查状态  全部状态与，如全状态为空/指定键不存在，返回 true
     * @param key 
     * @returns boolean 
     */
    check(key) {
        if (key) {
            return !this.states[key] || (this.states[key][0] == this.states[key][1]);
        }
        else {
            for (let key in this.states) {
                if (this.states[key][0] != this.states[key][1]) {
                    return false;
                }
            }
            return true;
        }
    }
};




module.exports = {
    Random,
    FakeRandom,
    RandomDraw,
    OrderDraw,
    Drawer,
    Attribute,
    UidCalculator,
    ArrayUtils,
    CollectionUtils,
    SyncState
};